#pragma once
#ifndef _MYLIST_H
#define _MYLIST_H

template <typename T> class MyList;
template <typename T> class ListIterator;

template <typename T>
class ListNode {

template <typename T>
friend class MyList;

template <typename T>
friend class ListIterator;

private:
	T val;
	ListNode* next;
	ListNode(const T& in) :val(in) {
		next = NULL;
	}
};

template <typename T>
class ListIterator {

public:
	ListIterator(const MyList<T>& l) :innerlist(l), cur(l.first) {};
	~ListIterator() {
		delete cur;
	};
	T* first();
	T* next();
	bool NotNull();
	bool NextNotNull();

private:
	const MyList<T>& innerlist;
	ListNode<T>* cur;
};

template <typename T>
class MyList {

template <typename T>
friend class ListIterator;

private:
	ListNode<T> *first;
public:
	MyList();
	~MyList();
	void insert(const T& val);
	void del(const T& num);
	void invert();
	void concat(MyList& another);
	void show();
};

template <typename T>
MyList<T>::MyList() {
	first = NULL;
}

template <typename T>
MyList<T>::~MyList() {
	delete first;
}

template <typename T>
void MyList<T>::insert(const T& val) {
	ListNode<T>* newnode = new ListNode<T>(val);
	newnode->next = first;
	first = newnode;
}

template <typename T>
void MyList<T>::del(const T& num) {
	if (first == NULL) {
		throw "The list is empty,Can not delete element!";
	}
	ListNode<T>* tmp = first;
	ListNode<T>* last = tmp;
	while (tmp != NULL) {
		if (tmp->val == num) {
			break;
		}
		last = tmp;
		tmp = tmp->next;
	}
	last->next = tmp->next;

}

template <typename T>
void MyList<T>::invert() {
	if (first == NULL) {
		throw "The list is empty,Can not invert!";
	}
	ListNode<T>* newfirst = nullptr;
	ListNode<T>* tmp=first;
	ListNode<T>* r = nullptr;
	while (tmp!=NULL) {
		r = newfirst;
		newfirst = new ListNode<T>(tmp->val);
		newfirst->next = r;
		tmp = tmp->next;
	}
	first = newfirst;
}

template <typename T>
void MyList<T>::concat(MyList& another) {
	if (another.first==NULL){
		if (first==NULL) {
			throw "The list is empty, Can not concat!";
		}else {
			return ;
		}
	}
	ListNode<T>* tmp = first;
	while (tmp->next!=NULL){
		tmp=tmp->next;
	}
	tmp->next = another.first;
}

template <typename T>
void MyList<T>::show() {
	ListNode<T>* tmp = first;
	while (tmp != NULL) {
		std::cout << tmp->val << "->";
		tmp = tmp->next;
	}
	std::cout << std::endl;
}

template <typename T>
T* ListIterator<T>::first() {
	if (innerlist.first != NULL) {
		return &(innerlist.first->val);
	} else {
		return nullptr;
	}
}

template <typename T>
T* ListIterator<T>::next() {
	if (cur != NULL&&cur->next != NULL) {
		cur = cur->next;
		return &(cur->val);
	}
	else{
		return nullptr;
	}
}

template <typename T>
bool ListIterator<T>::NotNull() {
	if (cur != NULL) {
		return true;
	}else {
		return false;
	}
}

template <typename T>
bool ListIterator<T>::NextNotNull() {
	if (NotNull() && cur->next != NULL) {
		return true;
	} else {
		return false;
	}
}

#endif // !_MYLIST_H
